/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
#include"PublicIPTool.h"
#include"PublicSocket.h"
#ifndef NOUSE_PUBLIC_LOG
#include"PublicLog.h"
#endif
#ifndef NOUSE_PUBLIC_DNS
#include"PublicDNS.h"
#endif
#include<errno.h>
#ifdef __MINGW32__
#include<winsock2.h>
#include<ws2tcpip.h>
#define USE_RECV_MSG 0
#define USE_SENDFILE 0
#define USE_SELECT_MODE 1
#else
//socket相关
#include<netinet/in.h>
//icmp相关
#include<netinet/ip_icmp.h>
#include<netinet/icmp6.h>
//IP装换相关
#include<arpa/inet.h>
#include<sys/poll.h>
#include<sys/epoll.h>
#include<sys/ioctl.h>
#include<sys/sendfile.h>
#include<netdb.h>
#define USE_RECV_MSG 1
#define USE_SENDFILE 1
//打印相关信息
#define SHOW_DEBUG_INFO 0
/*
int closesocket(SOCKET fd){
	return close(fd);
}
*/
#endif
//最后的套接字错误
int LastSocketErrno(){
#ifdef __MINGW32__
//10035 WSAEWOULDBLOCK 对应 	EINPROGRESS
//10060 WSAETIMEDOUT   超时	
	int ret=WSAGetLastError();
	//printf("%d %d\n",ret,errno);
	if(ret==10035)ret=EINPROGRESS;
	return ret;
#else
//11 EAGAIN	
	return errno;
#endif	
}
//type为POLLIN或POLLOUT
int _selectsocket(SOCKET sock,int timeoutms,int type){
	int status=0;
#if USE_SELECT_MODE
	//多线程下存在问题
	fd_set wrst;FD_ZERO(&wrst);FD_SET(sock,&wrst);
	struct timeval tmo;memset(&tmo,0,sizeof(tmo));tmo.tv_sec = timeoutms/1000;tmo.tv_usec=timeoutms%1000;
	if(type==POLLIN){
		status = select(sock +1,&wrst,NULL,NULL,timeoutms != 0 ? &tmo: NULL);
	}else{
		status = select(sock +1,NULL,&wrst,NULL,timeoutms != 0 ? &tmo: NULL);
	}
#else
	struct pollfd ufds;
	ufds.fd = sock;ufds.events = type;ufds.revents = 0;
	status=poll(&ufds,1,timeoutms);
#endif
	return status;
}
//同时判断sock4,sock6
int _selectsocket_new(SOCKET sock4,SOCKET sock6,int timeoutms,int type){
	int status=0;
	struct pollfd ufds[2];
	ufds[0].fd = sock4;ufds[0].events = type;ufds[0].revents = 0;
	ufds[1].fd = sock6;ufds[1].events = type;ufds[1].revents = 0;
	status=poll(ufds,2,timeoutms);
//不存在返回0
//都有返回4
//依次判断有没有
	if(status==1){
		if(ufds[0].revents!=0){
			return 4;
		}else
		if(ufds[1].revents!=0){
			return 6;
		}
	}else
	if(status==2){
		return 4;
	}	
	return status;
}

//合并 原_create_tcp_socket，_connect_socket
//对端IP及端口
#include<net/if.h>
int _create_tcp_connect(const char*ip,uint16_t port,SOCKET&sock,const char*bindip=NULL){
	int iptype=GetIPType(ip);
	sock=-1;
	if(iptype==6){
		sock=socket(AF_INET6,SOCK_STREAM,IPPROTO_TCP);
	}else
	if(iptype==4){
		sock=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
	}
	if(sock<0){
		WRONG("套接字创建失败For:%s Errno:%d",ip,LastSocketErrno());
		return -1;
	}
	//printf("sock:%d iptype:%d\n",sock,iptype);
//异步设置	
//效果不好
//	fcntl(sock,F_SETFL,fcntl(m_sock,F_GETFL) | O_NONBLOCK);//设置为非阻塞	
	u_long arg = 1;
	ioctlsocket(sock,FIONBIO,&arg);  
//断开立刻回收，防止大量timeout	
    struct linger so_linger={1,0};
    if(setsockopt(sock,SOL_SOCKET,SO_LINGER,(const char*)&so_linger,sizeof(struct linger))!=0){
		WRONG("setsockopt SO_LINGER err:%d",errno);
	}	
//绑源IP	
	if(bindip){
		int bindiptype=GetIPType(ip);
		if(bindiptype==iptype){
			if(bindiptype==6){
				struct sockaddr_in6 source={0};
				source.sin6_family = AF_INET6;
				inet_pton(AF_INET6,bindip,&source.sin6_addr);
				if(bind(sock,(struct sockaddr*)&source,sizeof(source))!=0){
					WRONG("bind6 %s err in connect errno:%d",bindip,LastSocketErrno());
				}
			}else
			if(bindiptype==4){
				struct sockaddr_in source={0};
				source.sin_family = AF_INET;
				source.sin_addr.s_addr=inet_addr(bindip);
				if(bind(sock,(struct sockaddr*)&source,sizeof(source))!=0){
					WRONG("bind4 %s err in connect errno:%d",bindip,LastSocketErrno());
				}
			}
		}
	}
//连接	
	if(iptype==6){
		struct sockaddr_in6 dest_addr={0};
		dest_addr.sin6_family=AF_INET6;
		dest_addr.sin6_port=htons(port);
		inet_pton(AF_INET6,ip,&dest_addr.sin6_addr);
		//fe80开头的ipv6需绑定网卡
		//非公有IP需绑定网卡
		if(IsPublicIPV6(ip)==0){
			const char *device=GetIPV6DeviceName();
			struct ifreq ifr;
			memset(&ifr, 0, sizeof(ifr));
			strncpy(ifr.ifr_name, device, IFNAMSIZ-1);
			if (setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, device, strlen(device)+1) == -1) {
				WRONG("SO_BINDTODEVICE %s ERR",device);
			}
		}
	//连接成功	
		return connect(sock,(struct sockaddr*)&dest_addr,sizeof(dest_addr));
	}else
	if(iptype==4){
		struct sockaddr_in dest_addr={0};
		dest_addr.sin_family=AF_INET;
		dest_addr.sin_port=htons(port);
		inet_pton(AF_INET,ip,&dest_addr.sin_addr);
	//连接成功	
		return connect(sock,(struct sockaddr*)&dest_addr,sizeof(dest_addr));
	}
	return -1;
}
//////////////////////通用函数///////////////////////////////////////
CPublicSocket::CPublicSocket(){
	m_sock=0;
	m_sock6=0;
	m_sync=0;
	m_timeoutms=0;
#ifndef __MINGW32__ 	
	m_epoll=0;
	m_maxevents=0;
	m_events=NULL;
#else
	FD_ZERO(&m_fdset);
	m_maxevents=0;
	m_events=NULL;
#endif	
}
CPublicSocket::~CPublicSocket(){
	CloseSocket();
}
void CPublicSocket::CloseSocket(){
	if(m_sock>0){	
		closesocket(m_sock);	
		m_sock=0;
	}
	if(m_sock6>0){	
		closesocket(m_sock6);	
		m_sock6=0;
	}
	m_timeoutms=0;
	m_sync=0;
#ifndef __MINGW32__ 	
	if(m_epoll>0){
		close(m_epoll);
		m_epoll=0;
	}
	m_maxevents=0;
	if(m_events){
		free(m_events);
		m_events=NULL;
	}
#endif	
}

int CPublicSocket::GetSocketName(char*ip){
	struct sockaddr_in addr={0};
	socklen_t len = sizeof(struct sockaddr_in);
	if(getsockname(m_sock, (struct sockaddr*)&addr, (socklen_t *)&len) < 0){
		return -1;
	}
	strcpy(ip,inet_ntoa(addr.sin_addr));
	return 0;
}
#ifndef ICMP_FILTER
#define ICMP_FILTER 1
struct icmp_filter {
	uint32_t	data;
};
#endif
//m_sockV4必须成功 m_sockV6可以失败
int CPublicSocket::CreateSocket(socket_type protocol,int timeoutms,const char*srcip){
	if(protocol==SOCKET_TYPE_ICMP){
		m_sock=socket(AF_INET,SOCK_RAW,IPPROTO_ICMP);	
		if(m_sock<0){
			WRONG("套接字 AF_INET IPPROTO_ICMP 创建失败:%d",LastSocketErrno());
			return -1;
		}
		m_sock6=socket(AF_INET6,SOCK_RAW,IPPROTO_ICMPV6);	
		if(m_sock6<0){
			WRONG("套接字 AF_INET6 IPPROTO_ICMPV6 创建失败:%d",LastSocketErrno());
			m_sock6=0;
		}
		INFO("icmp m_sock:%d m_sock6:%d %d",m_sock,m_sock6,errno);
#ifndef __MINGW32__	
#ifndef ICMP_ECHO
#define	ICMP_ECHO 8		
#endif		
//屏蔽ICMP请求
		if(1){
			//uint32_t         flag=1<<ICMP_ECHO;
			struct icmp_filter flag;
			//flag.data=1<<ICMP_ECHO;
//只捕获ICMP ICMP_ECHOREPLY 消息	,其余忽略
//捕获ICMP_TIME_EXCEEDED			
			flag.data=~((1<<ICMP_ECHOREPLY)|(1<<ICMP_TIME_EXCEEDED));
			if(setsockopt(m_sock,SOL_RAW,ICMP_FILTER,&flag,sizeof(struct icmp_filter))!=0){
				WRONG("setsockopt SOL_RAW ICMP_FILTER err");
			}
		}
//IPV6设置		
		if(0){
			int working_recverr = 1;
			int hold = 1;
			if (setsockopt(m_sock6, SOL_IPV6, IPV6_RECVERR, (char *)&hold, sizeof(hold))) {
				fprintf(stderr, "WARNING: your kernel is veeery old. No problems.\n");
				working_recverr = 0;
			}
			int csum_offset = 2;
			int sz_opt = sizeof(int);
			int err = setsockopt(m_sock6, SOL_RAW, IPV6_CHECKSUM, &csum_offset, sz_opt);
			if (err < 0) {
				perror("setsockopt(RAW_CHECKSUM)");
			}
			
			struct icmp6_filter filter;
			ICMP6_FILTER_SETBLOCKALL(&filter);
			if (!working_recverr) {
				ICMP6_FILTER_SETPASS(ICMP6_DST_UNREACH, &filter);
				ICMP6_FILTER_SETPASS(ICMP6_PACKET_TOO_BIG, &filter);
				ICMP6_FILTER_SETPASS(ICMP6_TIME_EXCEEDED, &filter);
				ICMP6_FILTER_SETPASS(ICMP6_PARAM_PROB, &filter);
			}
			//ICMP6_FILTER_SETPASS(ICMP6_ECHO_REQUEST, &filter);
			ICMP6_FILTER_SETPASS(ICMP6_ECHO_REPLY, &filter);
			if(setsockopt(m_sock6,IPPROTO_ICMPV6,ICMP6_FILTER,&filter,sizeof(struct icmp6_filter))!=0){
				WRONG("setsockopt6 IPPROTO_ICMPV6 ICMP6_FILTER err");
			}
		}
#endif			
	}else
	if(protocol==SOCKET_TYPE_UDP){
		m_sock=socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP);
		if(m_sock<0){
			WRONG("套接字 AF_INET IPPROTO_UDP 创建失败:%d",LastSocketErrno());
			return -1;
		}
		m_sock6=socket(AF_INET6,SOCK_DGRAM,IPPROTO_UDP);
		if(m_sock6<0){
			WRONG("套接字 AF_INET6 IPPROTO_UDP 创建失败:%d",LastSocketErrno());
			m_sock6=0;
		}
		INFO("udp m_sock:%d m_sock6:%d %d",m_sock,m_sock6,errno);
	}else{
		return -1;
	}
//接收超时设置
	if(timeoutms<1)timeoutms=1;
	m_timeoutms=timeoutms;
#ifdef __MINGW32__
	int tv=timeoutms;
	INFO("Set Recv TimeOut:%d ms",timeoutms);
#else	
	struct timeval  tv={timeoutms/1000,(timeoutms%1000)*1000};
	INFO("Set Recv TimeOut:%ld.%06ld(%d ms) ",tv.tv_sec,tv.tv_usec,timeoutms);
#endif	
	if(setsockopt(m_sock,SOL_SOCKET,SO_RCVTIMEO,(char*)&tv,sizeof(tv))!=0){
		WRONG("setsockopt SO_RCVTIMEO err");
    }	
//源IP设置	
	if(srcip!=NULL){
		if(IsIPV4(srcip)==1){
			struct sockaddr_in source={0};
			source.sin_family = AF_INET;
			inet_pton(AF_INET,srcip,&source.sin_addr);
			if(bind(m_sock,(struct sockaddr*)&source,sizeof(source))!=0){
				WRONG("绑定源IPV4:%s 失败 ERRNO:%d",srcip,LastSocketErrno());
			}
		}else
		if((m_sock6>0)&&(IsIPV6(srcip)==1)){
			struct sockaddr_in6 source={0};
			source.sin6_family = AF_INET6;
			inet_pton(AF_INET6,srcip,&source.sin6_addr);
			if(bind(m_sock6,(struct sockaddr*)&source,sizeof(source))!=0){
				WRONG("绑定源IPV6:%s 失败 ERRNO:%d",srcip,LastSocketErrno());
			}
		}else{
			WARN("not support bind ip:%s",srcip);
		}
    }
#if USE_RECV_MSG
	int flag=1;
    if(setsockopt(m_sock, SOL_SOCKET, SO_TIMESTAMP, &flag, sizeof(uint32_t))!=0){
		WRONG("setsockopt SOL_SOCKET SO_TIMESTAMP err");
    }
#endif		
	return 0;
}

int CPublicSocket::Recv(char*buff,int length,char*fromip,struct timeval*recvtimestamp,int*ipflag){
	int ret=IsReadEnableNew(m_timeoutms);	
	if(ret==4){
		struct sockaddr_in clientAddr={0};
		socklen_t socklen=sizeof(struct sockaddr_in);
		ret=recvfrom(m_sock,buff,length,0,(struct sockaddr*)&clientAddr,&socklen);	
		if(ret>0){
			if(fromip){
				inet_ntop(AF_INET,&clientAddr.sin_addr,fromip,16);
			}
			if(ipflag){
				*ipflag=4;
			}
			if(recvtimestamp){		
				//未生效
				//ioctl(m_sock,SIOCGSTAMP,recvtimestamp);
				gettimeofday(recvtimestamp,NULL);
			}
		}
#if SHOW_DEBUG_INFO
		char ipv4[40]={0};
		inet_ntop(AF_INET,&clientAddr.sin_addr,ipv4,40);
		WARN("IPV4 SOCK:%d Recv:%s Ret:%d Errno:%d",m_sock,ipv4,ret,errno);
#endif
	}else
	if(ret==6){
		struct sockaddr_in6 clientAddr={0};
		socklen_t socklen=sizeof(struct sockaddr_in6);
		ret=recvfrom(m_sock6,buff,length,0,(struct sockaddr*)&clientAddr,&socklen);	
		if(ret>0){
			if(fromip){
				inet_ntop(AF_INET6,&clientAddr.sin6_addr,fromip,40);
			}
			if(ipflag){
				*ipflag=6;
			}
			if(recvtimestamp){		
				gettimeofday(recvtimestamp,NULL);
			}
		}
#if SHOW_DEBUG_INFO
		char ipv6[40]={0};
		inet_ntop(AF_INET6,&clientAddr.sin6_addr,ipv6,40);
		WARN("IPV6 SOCK:%d Recv:%s Ret:%d Errno:%d",m_sock6,ipv6,ret,errno);
#endif
	}
	return ret;
}
int CPublicSocket::Send(char*buff,int length,const char*dstip,uint16_t dstport,int ttl){
	int ret=-1;
	if(IsIPV4(dstip)==1){
		struct sockaddr_in other={0};
		other.sin_family=AF_INET;
		other.sin_port=htons(dstport);
		inet_pton(AF_INET,dstip,&other.sin_addr);
		if(ttl>0){
			//IPPROTO_IP
			if(setsockopt(m_sock,SOL_IP,IP_TTL,(char*)&ttl,sizeof(ttl))!=0){
				WRONG("SetSockOpt IP_TTL %d Err\n",ttl);
			}
		}
		ret=sendto(m_sock,buff,length,0,(struct sockaddr*)&other,sizeof(struct sockaddr_in));
		if(ret==-1){
			WARN("IPV4 Send:%s Ret:%d %d",dstip,ret,errno);
		}
	}else
	if((m_sock6>0)&&(IsIPV6(dstip)==1)){
		struct sockaddr_in6 other={0};
		other.sin6_family=AF_INET6;
		other.sin6_port=htons(dstport);
		inet_pton(AF_INET6,dstip,&other.sin6_addr);
		if(ttl>0){
			if(setsockopt(m_sock6,SOL_IPV6,IPV6_UNICAST_HOPS,(char*)&ttl,sizeof(ttl))!=0){
				WRONG("SetSockOpt 6 IP_TTL %d Err\n",ttl);
			}
		}
		ret=sendto(m_sock6,buff,length,0,(struct sockaddr*)&other,sizeof(struct sockaddr_in6));
		if(ret==-1){
			WARN("IPV6 Send:%s Ret:%d %d",dstip,ret,errno);
		}
	}
#if SHOW_DEBUG_INFO	
	WARN("IP Send:%s Ret:%d %d",dstip,ret,errno);
#endif
	return ret;
}
int CPublicSocket::Connect(const char*server,uint16_t port,int timeoutms){
//优先判断是IP还是域名
	char     ip[40]={0};
//进行DNS解析	
	if(IsIPV4(server)==1||IsIPV6(server)==1){
		strcpy(ip,server);
	}else{
#ifndef NOUSE_PUBLIC_DNS		
		SETIPLIST dnslist;
		SLNode*result=dlgethostbyname(server,dnslist);
		if(result==NULL){
			WRONG("域名解析失败:%s",server);
			return -1;
		}else{
			strcpy(ip,result->next->data.host);
			//PrintDNSInfo(result,server);
			Destroy(&result);
			if(IsIPV4(ip)==0&&IsIPV6(ip)==0){
				WRONG("IP获取错误");
				return -1;
			}
		}
#else
		return -1;
#endif		
	}
	int r=_create_tcp_connect(ip,port,m_sock,NULL);
	if(r<0){
//不是异步进行中错误	
#if 1		
		int lasterr=LastSocketErrno();
		if(lasterr != EINPROGRESS){
			INFO("非理想情况 ret:%d errno:%d",r,lasterr);
			CloseSocket();
			return -1;
		}		
#endif		
//判断是否可写
		if(timeoutms<1)timeoutms=1;
		m_timeoutms=timeoutms;
		if(IsWriteEnable(m_timeoutms)<1){
			CloseSocket();
			return -1;
		}		
	}	
	return 0;
}

int CPublicSocket::IsReadEnable(int timeoutms){
	if(m_sync)return 1;
	return _selectsocket(m_sock,timeoutms,POLLIN);
}
int CPublicSocket::IsWriteEnable(int timeoutms){
	if(m_sync)return 1;
	return _selectsocket(m_sock,timeoutms,POLLOUT);
}
int CPublicSocket::IsReadEnableNew(int timeoutms){
	if(m_sock6>0){
		return _selectsocket_new(m_sock,m_sock6,timeoutms,POLLIN);
	}else
	if(IsReadEnable(timeoutms)==1){
		return 4;
	}	
	return 0;
}
int CPublicSocket::IsWriteEnableNew(int timeoutms){
	if(m_sock6>0){
		return _selectsocket_new(m_sock,m_sock6,timeoutms,POLLOUT);
	}else
	if(IsWriteEnable(timeoutms)==1){
		return 4;
	}	
	return 0;
}
//发送数据
int CPublicSocket::SendTCP(const char*buff,int length,int timeoutms){
//优先判断是否可写	
	int ret=0;
	do{
		if(IsWriteEnable(timeoutms)<1){
			return -1;
		}
		ret=send(m_sock,buff,length,0);
		if(ret>0){
			length-=ret;
			if(length==0){
				ret=0;
			}
		}
	}while(ret>0);
	return ret;
}
//接收数据 超时设置
int CPublicSocket::RecvTCP(char*buff,int length,int timeoutms){
//优先判断是否可读
	if(IsReadEnable(timeoutms)!=1){
		return -1;
	}
	int ret=recv(m_sock,buff,length,0);
	return ret;
}
//发送文件
//文件描述符，位置，剩余大小
int CPublicSocket::SendFile(int fd,int64_t*pos,size_t leftsize){
#if USE_SENDFILE	
	ssize_t ret=0;
	do{
		if(IsWriteEnable(1000)<1){
			return -1;
		}
//非阻塞会要一次性传完容易卡		
		ret=sendfile64(m_sock,fd,pos,leftsize);
		//INFO("Ret:%zd Pos:" PRI64 " left:%zd",ret,*pos,leftsize);
		if(ret>0){
			leftsize-=ret;
			if(leftsize==0){
				ret=0;
			}
		}
	}while(ret>0);
#else
	int ret=0;
	if(lseek64(fd,*pos,SEEK_SET)<0){
		return -1;
	}
	char buff[102400]={0};
	do{
		ret=read(fd,buff,sizeof(buff));
		if(ret>0){
			ret=SendTCP(buff,ret,5);
		}
	}while(ret>0);
#endif	
	return ret;
}
#ifndef __MINGW32__ 
int CPublicSocket::EpollCreate(int maxsize){
	m_maxevents=maxsize;
	m_epoll=epoll_create(m_maxevents);
	if(m_epoll==-1){
		WRONG("Create epoll_sock Error:%d",LastSocketErrno());
		return -1;
	}
	m_events=(struct epoll_event*)malloc(sizeof(struct epoll_event)*m_maxevents);
	if(m_events==NULL){
		close(m_epoll);
		WRONG("Create Events Error:%d",LastSocketErrno());
		return -1;
	}
	return 0;
}
struct epoll_event*CPublicSocket::EpollWait(int timeout,int&events){
	memset(m_events,0,sizeof(struct epoll_event)*m_maxevents);
	events=epoll_wait(m_epoll,m_events,m_maxevents,timeout);
	return m_events;
}
//-1失败 0直接连接成功 返回对应FD
SOCKET CPublicSocket::EpollConnect(const char*ip,uint16_t port,const char*src){
	SOCKET fd=-1;
//连接成功	
	if(_create_tcp_connect(ip,port,fd,src)==0){
		closesocket(fd);
		return 0;
	}
//异步导致的问题	
	if(LastSocketErrno()!=EINPROGRESS){
		closesocket(fd);
		WARN("EpollConnect ip:%s fd:%d Errno:%d",ip,fd,errno);
		return -1;
	}
//加入等待队列	
	struct epoll_event event={0};
    epoll_data_ex data;
    memset(&data,0,sizeof(epoll_data_ex));
    data.data.fd=(uint16_t)fd;
    data.data.port=port;
//ipv6这样不行	
    //data.data.addr=inet_addr(ip);
    event.data.u64=data.u64;
    event.events=EPOLLOUT|EPOLLONESHOT;
    epoll_ctl(m_epoll,EPOLL_CTL_ADD,fd,&event);
	return fd;
}
//移除套接字
int CPublicSocket::EpollDel(SOCKET fd){
	struct epoll_event event={0};
    event.events=EPOLLOUT|EPOLLONESHOT;
    int ret=epoll_ctl(m_epoll,EPOLL_CTL_DEL,fd,&event);
	closesocket(fd);
	return ret;
}
#else
int CPublicSocket::EpollCreate(int maxsize){	
	m_maxevents=maxsize;
	m_events=(struct epoll_event*)malloc(sizeof(struct epoll_event)*m_maxevents);
	if(m_events==NULL){
		WRONG("Create Events Error:%d",LastSocketErrno());
		return -1;
	}
	return 0;
}
struct epoll_event*CPublicSocket::EpollWait(int timeoutms,int&events){
	memset(m_events,0,sizeof(struct epoll_event)*m_maxevents);
	fd_set tmp=m_fdset;
	//INFO("AAA fd_count:%d timeout:%d ms",tmp.fd_count,timeoutms);
	//timeoutms=0会死等
	if(timeoutms<1)timeoutms=1;
	struct timeval tmo;memset(&tmo,0,sizeof(tmo));tmo.tv_sec = timeoutms/1000;tmo.tv_usec=timeoutms%1000;
	events = select(tmp.fd_count,NULL,&tmp,NULL,timeoutms != 0 ? &tmo: NULL);
	int i=0;
	//INFO("BBB events:%d fd_count:%d timeout:%d ms",events,tmp.fd_count,timeoutms);
	for(i=0;i<events;i++){
		m_events[i].data.data.fd=tmp.fd_array[i];
		struct sockaddr_in addr={0};
		socklen_t len = sizeof(struct sockaddr_in);
		if(getpeername(m_events[i].data.data.fd, (struct sockaddr*)&addr, (socklen_t *)&len) ==0){
			m_events[i].data.data.port=htons(addr.sin_port);
			m_events[i].data.data.addr=addr.sin_addr.s_addr;
		}	
		FD_CLR(m_events[i].data.data.fd,&m_fdset);
		m_events[i].events=EPOLLOUT;
	}
	return m_events;
}
//-1失败 0直接连接成功 返回对应FD
SOCKET CPublicSocket::EpollConnect(const char*ip,uint16_t port,const char*src){
	SOCKET fd=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
	if(fd==-1)return -1;
	//printf("%s:%hu %d\n",ip,port,fd);
	u_long arg = 1;
#ifdef __MINGW32__
	ioctlsocket(fd,FIONBIO,&arg);  
#else
	ioctl(fd,FIONBIO,&arg);
#endif	
    struct linger so_linger={1,0};
    setsockopt(fd,SOL_SOCKET,SO_LINGER,(const char*)&so_linger,sizeof(struct linger));
    if((src!=NULL)&&(strcmp(src,"0.0.0.0")!=0)){
		struct sockaddr_in source={0};
		source.sin_family = AF_INET;
		source.sin_addr.s_addr=inet_addr(src);
		if(bind(fd,(struct sockaddr*)&source,sizeof(source))!=0){
			WRONG("bind %s err in connect",src);
		}
    }
	
	struct sockaddr_in dest_addr={0};
	dest_addr.sin_family=AF_INET;
	dest_addr.sin_addr.s_addr=inet_addr(ip);
	dest_addr.sin_port=htons(port);
//连接成功	
	if(connect(fd,(struct sockaddr*)&dest_addr,sizeof(dest_addr))==0){
		closesocket(fd);
		return 0;
	}
//异步导致的问题	
	if(LastSocketErrno()!=EINPROGRESS){
		closesocket(fd);
		return -1;
	}
//加入等待队列	
	struct epoll_event event={0};
    epoll_data_ex data;
    memset(&data,0,sizeof(epoll_data_ex));
    data.data.fd=(int16_t)fd;
    data.data.port=port;
    data.data.addr=dest_addr.sin_addr.s_addr;
    event.data.u64=data.u64;
    event.events=EPOLLOUT|EPOLLONESHOT;
	FD_SET(fd,&m_fdset);
	return fd;
}
//移除套接字
int CPublicSocket::EpollDel(SOCKET fd){
	FD_CLR(fd,&m_fdset);
	closesocket(fd);
	return 0;
}
#endif
